package it.okkam.longwell.ui.command;

import java.io.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Properties;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.Vector;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.servlet.ServletContext;

import org.apache.log4j.Logger;
import org.apache.velocity.VelocityContext;

import com.hp.hpl.jena.query.Dataset;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.tdb.TDBFactory;
import com.hp.hpl.jena.tdb.store.Hash;

import edu.mit.simile.longwell.LongwellServer;
import edu.mit.simile.longwell.Profile;
import edu.mit.simile.longwell.corpus.Corpus;
import edu.mit.simile.longwell.corpus.TDBConnector;
import edu.mit.simile.longwell.login.CheckLogin;
import edu.mit.simile.longwell.query.Query;
import edu.mit.simile.longwell.query.Restriction;
import edu.mit.simile.longwell.query.bucket.Bucket;
import edu.mit.simile.longwell.query.bucket.BucketTheme;
import edu.mit.simile.longwell.schema.IStructuredSchema;
import edu.mit.simile.longwell.ui.FlairMessage;
import edu.mit.simile.longwell.ui.FlairURL;
import edu.mit.simile.longwell.ui.InjectionManager;
import edu.mit.simile.longwell.ui.command.CommandBase;

/**
 * 
 * @author nicola
 * classe che si occupa di aggiornare il modello in base ai grafi selezionati dall'utente
 */

public class ChangeModelCommand extends CommandBase {
	final static private Logger s_logger = Logger.getLogger(ChangeModelCommand.class);
	CheckLogin check=null;
	final protected String m_template;
	public static boolean userInput = false;
	VelocityContext vcContext = null;
	private Profile m_profile;
	private String[] m_graphsSelected ;
	private static HashMap<String, String[]> m_graphsSelectedFromSession = new HashMap<String, String[]>();
	ArrayList<String> tmp = new ArrayList<String>();
	private static HashMap<String,String[]> m_graphsPrevius = new HashMap<String, String[]>();
	/**
	 * @param injectionManager
	 */
	public ChangeModelCommand(InjectionManager injectionManager, Corpus corpus,ArrayList<Dataset> dataset,Profile profile,String template) {
		super(injectionManager);
		m_template = template;
		m_profile = profile;
	}

	/* (non-Javadoc)
	 * @see edu.mit.simile.flair.IFlairCommand#execute(edu.mit.simile.flair.FlairMessage)
	 */
	synchronized public void execute(FlairMessage msg) throws ServletException {
		s_logger.info("execute change model");
		HttpSession session = msg.m_request.getSession();
		String sessionId = session.getId();	
		m_profile = LongwellServer.getServer().getProfile(sessionId);

		//leggo tutti i grafi selezionati dall'utente
		m_graphsSelected = msg.m_request.getParameterValues("graphName");
		
		//elimino tutti i grafi dalla struttura, per poi inserirli nuovamente
		m_graphsSelectedFromSession.remove("graphsSelected"+sessionId);
		
		//aggiungo i grafi appena selezionati, in modo da avere la struttura corretta
		m_graphsSelectedFromSession.put("graphsSelected"+sessionId, m_graphsSelected);
		
		//setto in sessione i grafi selezionati per poi leggerli a livello velocity
		session.setAttribute("graphName", m_graphsSelected);

		HashMap<String, Dataset> hash = SelectGraphsCommand.getGraphsByDataset(sessionId);
		if (hash==null){
			try {
				msg.m_response.sendRedirect(new FlairURL(msg).changeCommandQuery("home","").toURLString());
			} catch (IOException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
		}
		
		
		else if (m_graphsSelectedFromSession.get("graphsSelected"+sessionId)!=null &&m_graphsSelectedFromSession.size()>0){
			//m=TDBFactory.createModel();
			
			Dataset ds = hash.get(m_graphsSelectedFromSession.get("graphsSelected"+sessionId)[0]);
			if(ds!=null){
				Model defaultModel = ds.getDefaultModel();
				Date date = new Date();
				s_logger.info("start loading default model "+date);
				m_profile.addData(defaultModel);
				date = new Date();
				s_logger.info("end loading default model "+date);				
			}
			
			//prima selezione, aggiungo tutti i grafi selezionati nella struttura previus senza controllare
			if(m_graphsPrevius.size()==0 || m_graphsPrevius.get(sessionId)==null){
				//ciclo su tutti i grafi e gli aggiungo al modello senza controllare niente, si tratta della prima selezione dell'utente
				for (int i=0; i<m_graphsSelectedFromSession.get("graphsSelected"+sessionId).length;i++){
					if(hash.get(m_graphsSelectedFromSession.get("graphsSelected"+sessionId)[i])!=null){
						Model model = hash.get(m_graphsSelectedFromSession.get("graphsSelected"+sessionId)[i]).getNamedModel(m_graphsSelectedFromSession.get("graphsSelected"+sessionId)[i]);
						Date date = new Date();
						s_logger.info("start loading graph "+i+" "+date);
						m_profile.addData(model);
						date = new Date();
						s_logger.info("end loading graph "+i+" "+date);
					}
				}
				//----------------------FINE CICLO----------------------------------------------------
				//aggiorno la struttura dei grafi selezionati precedentemente, cosi da poterla usare in futuro
				m_graphsPrevius.put(sessionId, getGraphsSelected("graphsSelected"+sessionId));
				try {
					//rimando alla browse senza filtri
					msg.m_response.sendRedirect(new FlairURL(msg).changeCommandQuery("browse","").toURLString());
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			//FINE CONTROLLO SU PRIMA SELEZIONE DA PARTE DELL'UTENTE
			
			
			//grafi selezionati precedentemente sono maggiori di quelli selezionati adesso.
			//Sono stati tolti dei grafi, quindi e' corretto cancellare tutti i filtri.
			else if(m_graphsPrevius.get(sessionId).length>getGraphsSelected("graphsSelected"+sessionId).length && getGraphsSelected("graphsSelected"+sessionId).length>0){				
				//capire quali grafi sono stati tolti per eliminarli dal modello
				checkGraphsToRemove(sessionId, hash);				
				//controllare se sono stati aggiunti grafi che non erano presenti al passo precedente
				checkGraphsToAdd(sessionId, hash);				
				//aggiorno la struttura dei grafi selezionati precedentemente
				m_graphsPrevius.remove(sessionId);
				m_graphsPrevius.put(sessionId, getGraphsSelected("graphsSelected"+sessionId));
				try {
					//rimando alla browse senza filtri
					msg.m_response.sendRedirect(new FlairURL(msg).changeCommandQuery("browse","").toURLString());
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}				
			}
			//FINE CONTROLLO SU GRAFI SELEZIONATI IN NUMERO MINORE RISPETTO ALLA SELEZIONE PRECEDENTE
			
			
			//il numero di grafi selezionati sono uguali o maggiori a quelli selezionati precedentemente.
			//E' necessario controllare i grafi per vedere se sono cambiati.
			else if(m_graphsPrevius.get(sessionId).length<=getGraphsSelected("graphsSelected"+sessionId).length && getGraphsSelected("graphsSelected"+sessionId).length>0){				
				boolean redirectReset=checkGraphsToRemove(sessionId, hash);
				checkGraphsToAdd(sessionId, hash);				
				//se ho solo aggiunto, chiamo la browse senza resettare la ricerca effettuata fino a quel momento
				if(!redirectReset &&msg.m_request.getParameterValues("redirectURL")!=null){
					String redirect = msg.m_request.getParameterValues("redirectURL")[0];
					try {					
						msg.m_response.sendRedirect(redirect);
					} catch (Exception e) {
						e.printStackTrace();
					}					
				}
				//altrimenti resetto la ricerca
				else{
					try {					
						msg.m_response.sendRedirect(new FlairURL(msg).changeCommandQuery("browse","").toURLString());
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
				m_graphsPrevius.remove(sessionId);
				m_graphsPrevius.put(sessionId, getGraphsSelected("graphsSelected"+sessionId));
			}
		}		
		else{
			try {
				m_graphsPrevius.remove(sessionId);
				msg.m_response.sendRedirect(new FlairURL(msg).changeCommandQuery("selectGrafi","").toURLString());
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	public static String[] getGraphsSelected(String sessionId){
		return m_graphsSelectedFromSession.get(sessionId);
	}
	
	public static void clearGraphsSelectedPrevius(String sessionId){
		m_graphsPrevius.remove(sessionId);
	} 
	
	//metodo che confronta i grafi selezionati adesso con quelli alla selezione precedente
	//per capire se ci sono grafi da eliminare
	private boolean checkGraphsToRemove(String sessionId, HashMap<String,Dataset> hash){
		boolean checkGraph=false;
		boolean redirectReset=false;
		for(int i=0;i<m_graphsPrevius.get(sessionId).length;i++){
			checkGraph = false;
			String graphPrev = m_graphsPrevius.get(sessionId)[i];
			for(int j=0;j<getGraphsSelected("graphsSelected"+sessionId).length;j++){
				String graph = getGraphsSelected("graphsSelected"+sessionId)[j];
				if(graphPrev.equals(graph)){
					checkGraph=true;
				}							
			}
			if(checkGraph)
				continue;
			else{
				//devo eliminare il grafo
				//controllo che il dataset sia rimasto invariato
				if( hash.get(graphPrev)!=null){
					Model model = hash.get(graphPrev).getNamedModel(graphPrev);
					m_profile.removeData(model);
					redirectReset = true;
				}
				else{
					//m_profile.removeData(m_profile.getModel());
					redirectReset = true;
				}
			}
		}
		return redirectReset;
	}
	
	
	//metodo che confronta i grafi selezionati adesso con quelli alla selezione precedente
	//per capire se ci sono grafi da aggiungere
	private boolean checkGraphsToAdd(String sessionId,HashMap<String,Dataset> hash){
		boolean checkGraph=false;
		for(int j=0;j<getGraphsSelected("graphsSelected"+sessionId).length;j++){
			checkGraph = false;
			String graph = getGraphsSelected("graphsSelected"+sessionId)[j];
			for(int i=0;i<m_graphsPrevius.get(sessionId).length;i++){
				String graphPrev = m_graphsPrevius.get(sessionId)[i];
				if(graphPrev.equals(graph)){
					checkGraph=true;
				}	
			}
			if(checkGraph)
				continue;
			else{
				//devo aggiungere il grafo
				Model model = hash.get(graph).getNamedModel(graph);
				m_profile.addData(model);
			}					
		}
		return checkGraph;
	}
}